﻿using Futajma.MigrationStudio.DataDefinition;
using Futajma.MigrationStudio.GenericPersistance;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace Futajma.MigrationStudio.SharePointPersistance
{
    //public delegate void ProgressUpdate(object sender, long currentStep);
    //public delegate void ProgressInit(object sender, long stepCount, string name);


    public class SharePoint2010Persistence// : GenericPersistance.Persistance
    {

        public const int FILE_READ_BUFFER_SIZE = 32768;


        public static bool CheckServerAvailability()
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);

            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Utils.GetAppSetting("AnalysisListTitle"));
            clientContext.Load(oList);
            clientContext.ExecuteQuery();

            return oList.ServerObjectIsNull != null;
        }

        public static ListItemCollection GetDocumentSets(string functionalCordinator, bool requestAsAdmin)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);
            Principal usr = clientContext.Web.EnsureUser(functionalCordinator);

            clientContext.Load(usr);
            clientContext.ExecuteQuery();

            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Utils.GetAppSetting("AnalysisListTitle"));

            CamlQuery camlQuery = new CamlQuery();

            if (requestAsAdmin)
            {
                camlQuery.ViewXml = string.Format(Utils.GetAppSetting("DocumentSetSelectionCAMLQueryAsAdmin"), Utils.GetAppSetting("ResponsibleFieldname"), usr.Id);
            }
            else
            {
                camlQuery.ViewXml = string.Format(Utils.GetAppSetting("DocumentSetSelectionCAMLQuery"), Utils.GetAppSetting("ResponsibleFieldname"), usr.Id);
            }
            ListItemCollection collListItem = oList.GetItems(camlQuery);

            clientContext.Load(collListItem,
                items => items.IncludeWithDefaultProperties(
                item => item.DisplayName));

            clientContext.ExecuteQuery();

            return collListItem;
        }

        public event ProgressInit ProgressInit;
        public event ProgressUpdate ProgressUpdate;

        void SendProgressInit(long stepCount, string name)
        {
            if (ProgressInit != null)
            {
                ProgressInit(this, stepCount, name);
            }
        }

        void SendProgressUpdate(long currentStep)
        {
            if (ProgressUpdate != null)
            {
                ProgressUpdate(this, currentStep);
            }
        }

        public NetworkCredential GetCurrentNetworkCredential()
        {
            return CredentialManager.Credentials;
        }

        private string CheckOrCreateApplicationFolder()
        {
            string appFolder = Path.GetTempPath() + "MappingTool";

            if (!System.IO.Directory.Exists(appFolder))
            {
                Directory.CreateDirectory(appFolder);
            }
            return appFolder;
        }

        private void CopyStream(Stream source, Stream destination, int fileSize)
        {

            byte[] buffer = new byte[FILE_READ_BUFFER_SIZE];
            //int bufferCount = 0;
            int steps = fileSize / FILE_READ_BUFFER_SIZE + 1;
            int bytesRead;
            long readed = 0;

            do
            {

                bytesRead = source.Read(buffer, 0, buffer.Length);
                readed += bytesRead;

                destination.Write(buffer, 0, bytesRead);

                SendProgressUpdate(readed / FILE_READ_BUFFER_SIZE);

            } while (bytesRead != 0);

        }

        public string LoadZipFileAndExtractToUserFolder(string fileName, int folderId)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);

            var folderPath = string.Format(@"{0}\{1}", CheckOrCreateApplicationFolder(), Path.GetRandomFileName());

            Directory.CreateDirectory(folderPath);

            var val = GetFileFromFolder(clientContext, folderId, fileName);

            if (val != null)
            {
                int fileSize = int.Parse((string)val["File_x0020_Size"]);
                var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, (string)val["FileRef"]);

                if (fileInfo != null && fileInfo.Stream != null)
                {
                    using (var stream = new MemoryStream())
                    {
                        SendProgressInit(fileSize / FILE_READ_BUFFER_SIZE, "Download file from dashboard");
                        CopyStream(fileInfo.Stream, stream, fileSize);
                        stream.Seek(0, SeekOrigin.Begin);

                        FastZip fz = new FastZip();
                        fz.ExtractZip(stream, folderPath, FastZip.Overwrite.Always, null, null, null, true, false);
                    }
                }
                else
                {
                    return null;
                }


                //if (fileInfo != null && fileInfo.Stream != null)
                //{
                //    using (var stream = System.IO.File.OpenWrite(string.Format(@"{0}\{1}", folderPath, fileName)))
                //    {
                //        CopyStream(fileInfo.Stream, stream);
                //        stream.Flush();
                //    }
                //}

                //ExtractFiles(string.Format(@"{0}\{1}", folderPath, fileName));
                return folderPath;
            }
            else
            {
                return null;
            }
        }

        public List<ListItem> GetSavedMigrationRecords(string functionalCordinator, bool requestAsAdmin)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);
            Principal usr = clientContext.Web.EnsureUser(functionalCordinator);

            clientContext.Load(usr);
            clientContext.ExecuteQuery();

            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Settings.MigrationListTitle);

            CamlQuery camlQuery = new CamlQuery();

            if (requestAsAdmin)
            {
                camlQuery.ViewXml = string.Format(Settings.MigrationSelectionCAMLQueryAsAdmin, Settings.MigrationResponsibleFieldname, usr.Id);
            }
            else
            {
                camlQuery.ViewXml = string.Format(Settings.MigrationSelectionCAMLQuery, Settings.MigrationResponsibleFieldname, usr.Id);
            }

            ListItemCollection collListItem = oList.GetItems(camlQuery);

            clientContext.Load(collListItem,
                items => items.IncludeWithDefaultProperties(
                item => item.DisplayName));

            clientContext.ExecuteQuery();

            List<ListItem> savedItems = new List<ListItem>();

            foreach (var item in collListItem)
            {
                var savedItem = GetFolderItem(clientContext, (string)item["FileRef"], oList, Settings.ProjectPersistenceDataItemTitle + ".zip");
                if (savedItem != null)
                {
                    savedItems.Add(item);
                }
            }

            return savedItems;
        }

        public ListItemCollection GetImportableMigrationRecords(string functionalCordinator, bool requestAsAdmin)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);
            Principal usr = clientContext.Web.EnsureUser(functionalCordinator);

            clientContext.Load(usr);
            clientContext.ExecuteQuery();

            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Settings.MigrationListTitle);

            CamlQuery camlQuery = new CamlQuery();

            if (requestAsAdmin)
            {
                camlQuery.ViewXml = string.Format(Settings.MigrationSelectionCAMLQueryAsAdmin, Settings.MigrationResponsibleFieldname, usr.Id);
            }
            else
            {
                camlQuery.ViewXml = string.Format(Settings.MigrationSelectionCAMLQuery, Settings.MigrationResponsibleFieldname, usr.Id);
            }
            ListItemCollection collListItem = oList.GetItems(camlQuery);

            clientContext.Load(collListItem,
                items => items.IncludeWithDefaultProperties(
                item => item.DisplayName));

            clientContext.ExecuteQuery();

            //MessageBox.Show(collListItem.Count.ToString());

            return collListItem;
        }

        public bool FileExistsInFolder(int folderId, string filename)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);
            var item = GetFileFromFolder(clientContext, folderId, filename);

            return item != null;
        }

        public ListItem GetFileFromFolder(ClientContext clientContext, int folderId, string filename)
        {

            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Settings.MigrationListTitle);

            ListItem item = oList.GetItemById(folderId);
            clientContext.Load(oList);
            clientContext.Load(item);
            clientContext.ExecuteQuery();

            var file = GetFolderItem(clientContext, (string)item["FileRef"], oList, filename);

            return file;
        }

        public string GetItemTitle(int itemId)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);
            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Settings.MigrationListTitle);

            ListItem item = oList.GetItemById(itemId);
            clientContext.Load(oList);
            clientContext.Load(item);
            clientContext.ExecuteQuery();

            return (string)item["Title"];
        }

        public static string GetFilePropertyPath(string filepath)
        {
            Uri fileUri = new Uri(filepath);
            string server = fileUri.AbsoluteUri.Replace(fileUri.AbsolutePath, "");

            ExtendedClientContext clientContext = new ExtendedClientContext(server);

            Uri fileSiteUri = Web.WebUrlFromPageUrlDirect(clientContext, fileUri);

            clientContext = new ExtendedClientContext(server + fileSiteUri.AbsolutePath);
            var web = clientContext.Site.OpenWeb(fileSiteUri.LocalPath);
            clientContext.Load(web);

            Microsoft.SharePoint.Client.File file = web.GetFileByServerRelativeUrl(fileUri.AbsolutePath);
            clientContext.Load(file);
            var item = file.ListItemAllFields;
            clientContext.Load(item);
            var list = item.ParentList;
            clientContext.Load(list);

            var folder = list.RootFolder;
            clientContext.Load(folder);
            
            clientContext.ExecuteQuery();

            var propertyPath = string.Format("{0}{1}/Forms/DispForm.aspx?ID={2}", server, folder.ServerRelativeUrl, item.Id );
            return propertyPath;
        }


        public ListItem GetFolderItem(ClientContext clientContext, string folderServerRelativeUrl, List list, string fileName)
        {
            Web oWebsite = clientContext.Web;
            ListCollection collList = oWebsite.Lists;

            List oList = collList.GetByTitle(Settings.MigrationListTitle);

            var query = new CamlQuery();

            query.FolderServerRelativeUrl = folderServerRelativeUrl;

            query.ViewXml = "<View Scope=\"RecursiveAll\"> " +
                "<Query>" +
                "<Where>" +
                 "<And>" +
                            "<Eq>" +
                                "<FieldRef Name=\"FileDirRef\" />" +
                                "<Value Type=\"Text\">" + folderServerRelativeUrl + "</Value>" +
                            "</Eq>" +
                            "<Eq>" +
                                "<FieldRef Name=\"FileLeafRef\" />" +
                                "<Value Type=\"Text\">" + fileName + "</Value>" +
                             "</Eq>" +
                 "</And>" +
                "</Where>" +
                "</Query>" +
                "</View>";

            var folderItems = list.GetItems(query);
            clientContext.Load(folderItems);
            clientContext.ExecuteQuery();

            if (folderItems.Count > 0)
            {
                return folderItems[0];
            }

            return null;
        }

        public bool EnsureUserInGroup(int groupId, string username)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);

            GroupCollection groupCollection = clientContext.Web.SiteGroups;

            Group grps = groupCollection.GetById(groupId);
            UserCollection users = grps.Users;

            clientContext.Load(users);
            clientContext.ExecuteQuery();

            //string userStr = username + "]";

            bool ret = false;

            foreach (var user in users)
            {
                //userStr += user.LoginName.ToLower() + ",";
                if (user.LoginName.ToLower() == username.ToLower())
                {
                    ret = true;
                }
            }

            //MessageBox.Show(userStr);

            return ret;

            //var user = users.GetByLoginName(username);

            //clientContext.Load(user);
            //clientContext.ExecuteQuery();

            //if (user != null)
            //{
            //    return true;
            //}
            //else
            //{
            //    return false;
            //}
        }

        public bool EnsureUserInGroup(int groupId)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);

            GroupCollection groupCollection = clientContext.Web.SiteGroups;

            Group grps = groupCollection.GetById(groupId);
            UserCollection users = grps.Users;

            clientContext.Load(users);
            clientContext.ExecuteQuery();

            //string userStr = username + "]";

            bool ret = false;

            var username = string.Format(@"{0}\{1}", CredentialManager.Credentials.Domain, CredentialManager.Credentials.Domain); 

            foreach (var user in users)
            {
                //userStr += user.LoginName.ToLower() + ",";
                if (user.LoginName.ToLower() == username.ToLower())
                {
                    ret = true;
                }
            }

            return ret;
        }

        public bool EnsureUserInMigrationTeamGroup(string username)
        {
            return EnsureUserInGroup(int.Parse(Settings.MigrationTeamGroupId), username);
        }

        public bool EnsureUserInMigrationTeamGroup()
        {
            return EnsureUserInGroup(int.Parse(Settings.MigrationTeamGroupId));
        }

        public static UserCollection GetAllUsersOfGroup(int groupId)
        {
            ExtendedClientContext clientContext = new ExtendedClientContext(Settings.MigrationPortalUrl);

            GroupCollection groupCollection = clientContext.Web.SiteGroups;

            Group grps = groupCollection.GetById(groupId);
            UserCollection users = grps.Users;

            clientContext.Load(users);
            clientContext.ExecuteQuery();

            return users;
        }
    }
}
